// File: jmcomic-core/src/main/java/dev/jukomu/common/postman/impl/Postmans.java
package dev.jukomu.common.postman.impl;

import dev.jukomu.common.base.registry.ComponentRegistry;
import dev.jukomu.common.postman.Postman;
import dev.jukomu.common.util.Asserts;
import dev.jukomu.common.util.net.ProxyBuilder;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * 对应Python的Postmans，Postman实例的工厂类。
 * 负责根据配置构建不同类型的Postman实例。
 */
public class Postmans {

    // 静态初始化块，在类加载时执行
    static {
        // 手动注册所有Postman的实现类
        ComponentRegistry.registerComponent(
                Postman.class, // 接口
                "POSTMAN_KEY", // 键字段名
                Arrays.asList( // 实现类列表
                        OkHttpPostman.class,
                        OkHttpSessionPostman.class,
                        CurlCffiPostman.class,
                        CurlCffiSessionPostman.class
                ),
                true // 要求必须有键字段
        );
    }

    /**
     * 获取Postman实现类的Class对象。
     *
     * @param key Postman的键名（例如 "okhttp", "curl_cffi"）
     * @return Postman实现类
     */
    public static Class<? extends Postman> getImplClass(String key) {
        return ComponentRegistry.getImplClass(Postman.class, key);
    }

    /**
     * 创建一个新的Session Postman实例。
     *
     * @param kwargs 初始化参数Map
     * @return Session Postman实例
     */
    public static Postman newSession(Map<String, Object> kwargs) {
        // Postman.create 是接口中的静态方法，无法直接调用
        // 我们需要通过反射来创建实例
        try {
            Class<? extends Postman> clazz = getImplClass(CurlCffiSessionPostman.POSTMAN_KEY);
            return clazz.getConstructor(Map.class).newInstance(kwargs);
        } catch (Exception e) {
            throw new RuntimeException("Failed to create new session postman", e);
        }
    }

    /**
     * 创建一个新的非Session Postman实例。
     *
     * @param kwargs 初始化参数Map
     * @return Postman实例
     */
    public static Postman newPostman(Map<String, Object> kwargs) {
        try {
            Class<? extends Postman> clazz = getImplClass(CurlCffiPostman.POSTMAN_KEY);
            return clazz.getConstructor(Map.class).newInstance(kwargs);
        } catch (Exception e) {
            throw new RuntimeException("Failed to create new postman", e);
        }
    }

    /**
     * 根据配置文件数据创建Postman实例。
     *
     * @param filepath 配置文件路径
     * @param data     配置数据Map（可选，如果为null则从文件加载）
     * @return Postman实例
     * @throws AssertionError 如果配置文件为空
     */
    public static Postman create(String filepath, Map<String, Object> data) {
        if (data == null) {
            try {
                data = (Map<String, Object>) dev.jukomu.common.base.packer.PackerUtils.unpack(filepath);
            } catch (IOException | ClassNotFoundException e) {
                throw new RuntimeException("Failed to unpack Postman config from file: " + filepath, e);
            }
            Asserts.requireTrue(data != null, "Empty config file path: " + filepath);
        }

        return new PostmanDslBuilder().buildPostman(data);
    }

    /**
     * 根据配置数据Map创建Postman实例。
     *
     * @param data 配置数据Map
     * @return Postman实例
     */
    public static Postman create(Map<String, Object> data) {
        return new PostmanDslBuilder().buildPostman(data);
    }

    /**
     * 对应Python的PostmanDslBuilder，用于解析DSL配置并构建Postman。
     */
    protected static class PostmanDslBuilder {

        // 处理器列表，按顺序处理DSL配置
        private final List<Function<Map<String, Object>, Postman>> dslHandlerList;

        public PostmanDslBuilder() {
            dslHandlerList = new java.util.ArrayList<>();
            // 将处理器按优先级添加到列表中
            // proxyHandler 修改数据，应在implTypeHandler之前
            dslHandlerList.add(this::proxyHandler);
            // implTypeHandler 返回 Postman，应在最后处理
            dslHandlerList.add(this::implTypeHandler);
        }

        /**
         * 处理代理配置。
         *
         * @param data 配置数据Map
         * @return null，此处理器只修改data，不直接返回Postman实例
         */
        private Postman proxyHandler(Map<String, Object> data) {
            Map<String, Object> metaData = (Map<String, Object>) data.computeIfAbsent("meta_data", k -> new HashMap<>());
            Object proxiesConfig = metaData.get("proxies");

            if (proxiesConfig == null || proxiesConfig instanceof Map) {
                return null;
            }

            if (proxiesConfig instanceof String) {
                metaData.put("proxies", ProxyBuilder.buildByStr((String) proxiesConfig));
            }

            return null;
        }

        /**
         * 处理Postman实现类型。
         *
         * @param dslData DSL配置数据Map
         * @return 构建的Postman实例
         * @throws UnsupportedOperationException 如果不支持的Postman类型
         */
        private Postman implTypeHandler(Map<String, Object> dslData) {
            Map<String, Object> metaData = (Map<String, Object>) dslData.computeIfAbsent("meta_data", k -> new HashMap<>());
            String implType = (String) dslData.getOrDefault("type", OkHttpPostman.POSTMAN_KEY); // 默认使用okhttp

            if ((implType.startsWith("okhttp") || implType.startsWith("requests")) && metaData.containsKey("impersonate")) {
                System.err.println("Warning: 'impersonate' parameter removed for OkHttp/Requests Postman type as it's specific to curl_cffi.");
                metaData.remove("impersonate");
            }

            Class<? extends Postman> clazz = getImplClass(implType);
            try {
                return clazz.getConstructor(Map.class).newInstance(metaData);
            } catch (Exception e) {
                throw new UnsupportedOperationException("Failed to create Postman instance for type: " + implType, e);
            }
        }

        /**
         * 构建Postman实例的入口方法。
         *
         * @param data 配置数据Map
         * @return 构建的Postman实例
         * @throws UnsupportedOperationException 如果没有找到合适的处理器来构建Postman
         */
        public Postman buildPostman(Map<String, Object> data) {
            // 复制一份数据，避免修改原始Map
            Map<String, Object> dataCopy = new HashMap<>(data);

            for (Function<Map<String, Object>, Postman> handler : dslHandlerList) {
                Postman postman = handler.apply(dataCopy);
                if (postman != null) {
                    return postman;
                }
            }
            // 默认情况下，implTypeHandler应该总是返回一个Postman实例
            throw new UnsupportedOperationException("No suitable handler found to build Postman for data: " + data);
        }
    }
}